/*
power by ignis
用于注册和运行子应用
 */
import {
  registerMicroApps,
  runAfterFirstMounted,
  start,
  RegistrableApp
} from 'qiankun'
// import { RegistrableApp } from 'qiankun/dist/interfaces'
import Vue from 'vue'

// import {Prop} from "vue/types/options";

export interface AppMap {
  [key: string]: Vue | any
}

interface Props {
  [key: string]: any
}

export interface RegisterAppsData {
  name: string
  localhost: string
  entry: string
  activeRule: string
  props?: regProps
}

export interface RenderProps {
  appContent: string;
  loading: boolean;
}

interface regProps {
  isInFramework: boolean,
  appCallback?: (appInstance: Vue | any) => void

  [key: string]: any
}

declare module 'vue/types/vue' {
  interface Vue {
    $regApp: RegApp,
    $afterMount: (instance: any) => void
  }
}

/***
 *
 * @param routerPrefix： 传入的用于判断子应用的路由
 * @param mode： 模式，子应用是hash模式还是history模式
 */
function genActiveRule(routerPrefix: string, mode: string = 'hash'): (location: Location) => boolean {
  return (location: Location) => {
    if (mode === 'hash') {
      const hash = location.hash.split('/')[1]
      return hash === routerPrefix.substr(2)
    } else {
      const path = location.hash.split('/')[1]
      return path === routerPrefix.substr(2)
    }
  }
}

// 用于自动判断当前路径是否是dev几或pre，如果是，把dev几或pre放在path的前面,并输出//dev.xxx.xxx.com
export function buildEntry(path: string): string {
  const host = location.host
  const hostPrefix = host.split('.')[0] // host前缀
  if (host.startsWith('localhost') || host.startsWith('127.0.0.1')) {
    return `//${path}`
  } else if (hostPrefix.startsWith('dev') || hostPrefix.startsWith('test') || hostPrefix.startsWith('pre')) {
    return `//${hostPrefix}.${path}`
  } else {
    return `//${path}`
  }
}

// const test = buildEntry('pro.s-gsun.com')
// console.log('test->', test)

export class RegApp {
  public frkInstance?: Vue
  public appMap: AppMap = {}
  public curAppInstance?: Vue | any
  // 子应用的注册信息
  public registerAppsData!: RegisterAppsData[]

  public lastContent: string = ''
  public isStart: boolean = false
  public renderCallback!: (html: string) => void
  public afterMountCallback?: (instance: Vue, props: Props) => void
  public afterUnMountCallback?: (instance: Vue, props: Props) => void
  public firstMountedCallback?: () => void

  // 构造函数
  constructor(instance: Vue, regData: RegisterAppsData[]) {
    this.frkInstance = instance
    this.registerAppsData = regData
    this.startApp()
    // setDefaultMountApp(this.registerAppsData[0].activeRule)
    // runAfterFirstMounted(this.firstMounted)
  }

  /***
   *
   * @param appContent 子app读取过来的html内容
   * @param loading 读取进度条，读取中返回true，读取完毕返回false
   */
  private render({ appContent, loading }: RenderProps): void {
    if (this.lastContent !== appContent) {
      this.lastContent = appContent
      if (this.renderCallback) {
        this.renderCallback(this.lastContent)
      }
    }
  }

  // 回调函数
  private beforeLoad(props: Props): Promise<void> {
    // console.log('before load', app)
    return Promise.resolve()
  }

  // 回调函数
  private beforeMount(props: Props): Promise<void> {
    // console.log('before mount', app)
    return Promise.resolve()
  }

  // qiankun的挂载回调
  private afterMount = (props: Props): Promise<void> => {
    // console.log(`${app.name} afterMount:`, app)
    if (this.afterMountCallback) {
      this.afterMountCallback(this.curAppInstance, props)
    }
    return Promise.resolve()
  }

  // qiankun的卸载回调
  private afterUnmount = (props: Props): Promise<void> => {
    // console.log(`${app.name} afterUnmount`, app)
    if (this.afterUnMountCallback) {
      this.afterUnMountCallback(this.curAppInstance, props)
    }
    return Promise.resolve()
  }

  // 注册子APP
  private regApps(regData: RegisterAppsData[]) {
    /* const jsonStr = JSON.stringify(regData.map(item => {
      return Pr
    })) */
    // console.dir(jsonStr)
    const apps = regData.map(item => {
      const app: RegistrableApp<Props> = {
        name: item.name,
        entry: process.env.NODE_ENV === 'development' ? `//${item.localhost}` : buildEntry(item.entry),
        render: this.render.bind(this),
        activeRule: genActiveRule(item.activeRule),
        props: {
          isInFramework: true,
          frkInstance: this.frkInstance,
          appCallback: (appInstance: Vue) => {
            this.appMap[item.name] = appInstance
            this.curAppInstance = appInstance
          }
        }
      }
      return app
    })
    registerMicroApps(apps, {
      beforeLoad: this.beforeLoad,
      afterMount: this.afterMount,
      beforeMount: this.beforeMount,
      afterUnmount: this.afterUnmount
    })
    runAfterFirstMounted(() => {
      if (this.firstMountedCallback) {
        this.firstMountedCallback()
      }
    })
  }

  // 开始挂载-一次执行
  public startApp() {
    if (!this.isStart) {
      console.log('regApp->开始')
      this.regApps(this.registerAppsData)
      start({ jsSandbox: false })
      this.isStart = true
    }
  }

  // 首次挂在（没什么卵用）
  public firstMounted(callback: () => void) {
    this.firstMountedCallback = callback
  }

  // 子项目渲染后
  public renderApp(callback: (html: string) => any) {
    this.renderCallback = callback
  }

  // 子项目挂载后
  public renderAfterMount(callback: (app: Vue, props: Props) => void) {
    this.afterMountCallback = callback
  }

  // 子项目卸载后
  public renderAfterUnMount(callback: (app: Vue, props: Props) => void) {
    this.afterUnMountCallback = callback
  }

  // 获取加载进来的Vue实列
  public getAppVueInstance(appName: string) {
    return this.appMap[appName].instance
  }
}

export default RegApp
